/**
 * @Title: AlipayServiceImpl.java
 * @Package com.leesche.zcsp.node.pay.alipay.service.impl
 * @Description:()
 * @author dennies yang
 * @date 2016年10月11日 下午5:12:56
 * @version V1.0
 */
package com.leesche.zcsp.node.pay.alipay.service.impl;

import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.AlipayConstants;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipaySystemOauthTokenRequest;
import com.alipay.api.response.AlipaySystemOauthTokenResponse;
import com.leesche.zcsp.node.net.service.NetService;
import com.leesche.zcsp.node.pay.alipay.service.AlipayService;
import com.leesche.zcsp.node.pay.wecha.data.Message;
import com.leesche.zcsp.node.pay.wecha.data.Oauth2To;
import com.leesche.zcsp.node.utils.*;
import com.leesche.zcsp.node.web.constants.Constants;
import com.leesche.zcsp.node.web.model.PubDevice;
import com.leesche.zcsp.node.web.model.PubDiscount;
import com.leesche.zcsp.node.web.model.ServOrder;
import com.leesche.zcsp.node.web.service.PubDeviceService;
import com.leesche.zcsp.node.web.service.PubDiscountService;
import com.leesche.zcsp.node.web.service.ServOrderService;
import com.leesche.zcsp.node.web.service.impl.data.writ.UpdateServOrderCommad;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.net.URLEncoder;
import java.util.*;

/**
 * @author dennies yang
 * @version V1.0
 * @Title: AlipayServiceImpl.java
 * @Package com.leesche.zcsp.node.pay.alipay.service.impl
 * @Description:()
 * @date 2016年10月11日 下午5:12:56
 */
@Service
public class AlipayServiceImpl implements AlipayService {
    private static final Logger LOGGER = Logger.getLogger(AlipayServiceImpl.class);

    @Autowired
    private ServOrderService serviceOrderService;

    @Autowired
    private NetService netService;

    @Autowired
    private PubDiscountService pubDiscountService;

    @Autowired
    private PubDeviceService pubDeviceService;

    private static String buildRequestMysign(Map<String, String> sPara) {
        String prestr = AlipayCore.createLinkString(sPara); // 把数组所有元素，按照“参数=参数值”的模式用“&”字符拼接成字符串
        String mysign = "";
        if (AlipayConfig.sign_type.equals("MD5")) {
            mysign = MD5.sign(prestr, AlipayConfig.key, AlipayConfig.input_charset);
        }
        return mysign;
    }

    public static Map<String, String> getRequestParams(HttpServletRequest request) {
        Map<String, String> params = new HashMap<String, String>();
        if (null != request) {
            Set<String> paramsKey = request.getParameterMap().keySet();
            for (String key : paramsKey) {
                params.put(key, request.getParameter(key));
            }
        }
        return params;
    }

    public static String encryptAndSign(String bizContent, String alipayPublicKey, String cusPrivateKey, String
            charset, boolean isEncrypt, boolean isSign, String signType) throws
                                                                                                                                                                             AlipayApiException {
        StringBuilder sb = new StringBuilder();
        if (StringUtils.isEmpty(charset)) {
            charset = AlipayConstants.CHARSET_UTF8;
        }
        sb.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>");
        if (isEncrypt) {// 加密
            sb.append("<alipay>");
            String encrypted = AlipaySignature.rsaEncrypt(bizContent, alipayPublicKey, charset);
            sb.append("<response>" + encrypted + "</response>");
            sb.append("<encryption_type>AES</encryption_type>");
            if (isSign) {
                String sign = AlipaySignature.rsaSign(encrypted, cusPrivateKey, charset, signType);
                sb.append("<sign>" + sign + "</sign>");
                sb.append("<sign_type>");
                sb.append(signType);
                sb.append("</sign_type>");
            }
            sb.append("</alipay>");
        } else if (isSign) {// 不加密，但需要签名
            sb.append("<alipay>");
            sb.append("<response>" + bizContent + "</response>");
            String sign = AlipaySignature.rsaSign(bizContent, cusPrivateKey, charset, signType);
            sb.append("<sign>" + sign + "</sign>");
            sb.append("<sign_type>");
            sb.append(signType);
            sb.append("</sign_type>");
            sb.append("</alipay>");
        } else {// 不加密，不加签
            sb.append(bizContent);
        }
        return sb.toString();
    }

    @Override
    public Map<String, String> orderAlipay(ServOrder order) {
        String body = (order.getCashFee() / 100) + "元" + order.getCoin() + "币";
        Map<String, String> alipayParams = new HashMap<String, String>();
        alipayParams.put("service", AlipayConfig.service);
        alipayParams.put("partner", AlipayConfig.partner);
        alipayParams.put("seller_id", AlipayConfig.seller_id);
        alipayParams.put("_input_charset", AlipayConfig.input_charset);
        alipayParams.put("payment_type", AlipayConfig.payment_type);
        alipayParams.put("notify_url", AlipayConfig.notify_url);
        alipayParams.put("return_url", AlipayConfig.return_url);
        alipayParams.put("out_trade_no", order.getOutTradeNo());
        alipayParams.put("subject", body);
        alipayParams.put("total_fee", String.valueOf(((float) order.getCashFee()) / 100));
//		alipayParams.put("total_fee", "0.01");
        alipayParams.put("show_url", "");
        alipayParams.put("body", body);
        String mysign = buildRequestMysign(AlipayCore.paraFilter(alipayParams));

        alipayParams.put("sign", mysign);
        alipayParams.put("sign_type", AlipayConfig.sign_type);
        return alipayParams;
    }

    public Message<String> notifyAlipay(Map requestParams, String out_trade_no, String trade_no, String trade_status) {
        Map<String, String> params = this.getAlipayRequestParams(requestParams);

        if (AlipayNotify.verify(params)) {// 验证成功

            if (!trade_status.equals("TRADE_SUCCESS")) {
                return Message.error("fail", new Object[0]);
            }
            //取出订单
            ServOrder servOrder = serviceOrderService.findServOrderByOrderNo(out_trade_no);
            PubDevice pubDevice = pubDeviceService.selectByPrimaryKey(servOrder.getDeviceid());
            //调用出币流程
            if (servOrder != null && pubDevice != null) {
//				LOGGER.info("支付宝启动");
                LOGGER.info("支付宝回调通知成功,准备发送指令给设备:" + pubDevice.getImme());
                netService.sendClientBuy(pubDevice, servOrder.getCashFee() / 100, servOrder
                        .getCoin(), PayConfig.PAY_ALIPAY, servOrder);
            }

            //更新订单状态
            serviceOrderService
                    .updateServOrderByOrderNo(new UpdateServOrderCommad(Constants.WECHAT_SUCCESS, trade_no,
                            out_trade_no));
//            LOGGER.info("订单号：trade_no" + trade_no);
//            LOGGER.info("订单号： out_trade_no " + out_trade_no);

            payNotify(out_trade_no, trade_no);
            LOGGER.info("zhi fubao notfiy success"); // 请不要修改或删除

            return Message.success("success", new Object[0]);
        } else {// 验证失败
            LOGGER.info("zhi fubao notfiy fail");
            return Message.error("fail", new Object[0]);
        }

    }

    @Override
    public String getAlipayRedirectUrl(String url) {
        return PayConfig.ALIPAY_AUTHVIEW.replace("APPID", PayConfig.ALIPAY_APPID)
                                        .replace("ENCODED_URL", URLEncoder.encode(url));
    }

    @Override
    public Message<Oauth2To> getOauth(String code) {
        AlipayClient alipayClient = new DefaultAlipayClient(PayConfig.ALIPAY_GATEWAY, PayConfig.ALIPAY_APPID,
                PayConfig.ALIPAY_APP_PRIVATE_KEY, "json", "UTF-8", PayConfig.ALIPAY_PUBLIC_KEY, PayConfig
                .ALIPAY_SIGN_TYPE);
        AlipaySystemOauthTokenRequest oauthTokenRequest = new AlipaySystemOauthTokenRequest();
        oauthTokenRequest.setCode(code);
        oauthTokenRequest.setGrantType("authorization_code");
        try {
            AlipaySystemOauthTokenResponse oauthTokenResponse = alipayClient.execute(oauthTokenRequest);

            if (null != oauthTokenResponse && oauthTokenResponse.isSuccess()) {
                LOGGER.info("获取支付宝用户信息成功：userId=" + oauthTokenResponse.getAlipayUserId());
//                LOGGER.info(oauthTokenResponse.toString());
                Oauth2To oauth2To = new Oauth2To();
                oauth2To.setOpenid(oauthTokenResponse.getAlipayUserId());
                oauth2To.setAccess_token(oauthTokenResponse.getAccessToken());
                oauth2To.setExpires_in(Integer.valueOf(oauthTokenResponse.getExpiresIn()));
                oauth2To.setRefresh_token(oauthTokenResponse.getRefreshToken());
//                oauth2To.setScope(oauthTokenResponse.get);
                return Message.success(oauth2To, null);
            } else {
                LOGGER.info("获取支付宝用户信息失败");
            }
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public String verifyAlipayGateWay(HttpServletRequest request) {
        Map<String, String> params = getRequestParams(request);
        LOGGER.info("支付宝网关验证请求串:" + params.toString());

        String responseMsg = "";
        try {
            this.verifySign(params);

            StringBuilder builder = new StringBuilder();
            builder.append("<success>").append(Boolean.TRUE.toString()).append("</success>");
            builder.append("<biz_content>").append(PayConfig.ALIPAY_APP_PUBLIC_KEY).append("</biz_content>");

            responseMsg = encryptAndSign(builder.toString(), PayConfig.ALIPAY_PUBLIC_KEY,
                    PayConfig.ALIPAY_APP_PRIVATE_KEY, "UTF-8", false, true, PayConfig.ALIPAY_SIGN_TYPE);
        } catch (AlipayApiException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return responseMsg;
    }

    /***
     * @Title: getAlipayRequestParams @Description: TODO(获取请求参数) @param @param
     * requestParams request请求参数怒 @param @return @return
     * Map<String,String> @throws
     */
    private Map<String, String> getAlipayRequestParams(Map requestParams) {
        Map<String, String> params = new HashMap<String, String>();
        for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext(); ) {
            String name = (String) iter.next();
            String[] values = (String[]) requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
            }
            params.put(name, valueStr);
            LOGGER.info("AlipayRequestParams:" + name + "=" + valueStr);
        }
        return params;
    }

    private void payNotify(String orderNo, String transactionid) {
        ServOrder orderData = serviceOrderService.findServOrderByOrderNo(orderNo);
        Integer state = orderData.getTradeState();
        if (state.intValue() != Constants.WECHAT_NOTPAY) {
            LOGGER.info("order no:" + orderNo + "+order.getTradeState() != STATE_ORDER");
            return;
        }
        LOGGER.info("order no:" + orderNo + "notify回调成功");
        orderData.setTradeStateDesc("支付宝订单被处理成功");
        orderData.setTimeEnd(new Date());
        orderData.setTransactionId(transactionid);
        orderData.setTradeState(Constants.WECHAT_SUCCESS);
        PubDiscount discount = pubDiscountService.selectByPrimaryKey(orderData.getDiscountid());
        int coin = discount.getCoin();
        LOGGER.info("发送货币coin:" + coin);
        int orderid = 2;// 记录序号

        int buyType = 1;
        int money = orderData.getCashFee() / 100;
        PubDevice pubDevice = pubDeviceService.selectByPrimaryKey(orderData.getDeviceid());
        // netService.sendBuy(pubDevice.getDid(), orderid,
        // orderData.getDeviceid(), buyType, (short) money, (short) coin);
    }

    private void verifySign(Map<String, String> params) throws AlipayApiException {
        if (!AlipaySignature.rsaCheckV2(params, PayConfig.ALIPAY_PUBLIC_KEY, "UTF-8", PayConfig.ALIPAY_SIGN_TYPE)) {
            throw new AlipayApiException("verify sign fail.");
        }
    }
}
